import { exportFile } from 'quasar';
import { boot } from 'quasar/wrappers';
import axios, { AxiosInstance, AxiosResponse } from 'axios';
import qs from 'qs';

import { Message, MessageBox, MessageType } from './message';
import { useUserStore } from 'src/stores';

declare module '@vue/runtime-core' {
  interface ComponentCustomProperties {
    $axios: AxiosInstance;
    $api: AxiosInstance;
  }
}

const isDevelopment = process.env.NODE_ENV === 'development';

// 创建 axios 实例
const service = axios.create({
  baseURL: process.env.APP_BASE_API,
  timeout: isDevelopment ? 50000 : 5000,
  headers: { 'Content-Type': 'application/json;charset=utf-8' },
  paramsSerializer: {
    serialize: (params) => qs.stringify(params, { arrayFormat: 'indices', allowDots: true }),
  },
});

// 请求拦截器
service.interceptors.request.use(
  (config) => {
    const token = useUserStore().token;
    if (token && config.headers) {
      config.headers.Authorization = 'Bearer ' + token;
    }
    return config;
  },
  (error) => {
    console.error('axios 请求异常');
    Message.error(error);
    return Promise.reject(error);
  },
);

// 响应拦截器
service.interceptors.response.use(
  //response code 2XX
  (response) => {
    // 开发环境记录下日志
    if (import.meta.env.DEV) {
      console.log(`Response[${response.config.url}]:`, response.data);
    }
    // 刷新token
    if (response.headers['fn-refresh-token']) {
      const userStore = useUserStore();
      userStore.refreshToken(response.headers['fn-refresh-token']);
    }
    // 文件下载时返回整个response，以便获取文件名，其它直接返回响应数据
    return response.data instanceof ArrayBuffer || response.data instanceof Blob ? response : response.data;
  },
  (error) => {
    if (!error.response) {
      Message.error('服务器没有响应，请检查请求地址是否正确。\n' + error.message);
      return Promise.reject(error);
    }

    const { status, statusText, data } = error.response;
    // 未登录或token 过期,重新登录
    if (status === 401) {
      const userStore = useUserStore();
      MessageBox.confirm('当前页面已失效，请重新登录', '提示').onOk(() => {
        userStore.doLogout().finally(() => (location.href = '#/login'));
      });
      return Promise.reject(error);
    }

    if (status === 403) {
      Message.warning('没有操作权限');
      return Promise.reject(error);
    }

    let msgType = (data.type?.toLowerCase() ?? 'error') as MessageType;
    //下载文件出错，读取json里的错误信息
    if (data instanceof Blob) {
      const reader = new FileReader();
      reader.onload = () => {
        const msg = JSON.parse(reader.result as string);
        msgType = (msg?.type?.toLowerCase() || 'error') as MessageType;
        Message[msgType](msg.message || msg);
      };
      reader.readAsText(data);
    } else if (status === 422) {
      // 422后台逻辑验证不通过，返回的错误提示信息。
      Message[msgType](data.message);
    } else {
      console.error('响应异常：', error.response);
      Message.error(data.message || statusText || '响应异常');
    }
    return Promise.reject(error.message);
  },
);

// 下载blob文件
export function downloadBlobFile(response: AxiosResponse, fileName = '') {
  const { data } = response;
  if (!fileName) {
    fileName = getFileNameFromResponse(response);
  }
  const url = window.URL.createObjectURL(data);
  const link = document.createElement('a');
  link.style.display = 'none';
  link.href = url;
  link.setAttribute('download', fileName);
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}

export function getFileNameFromResponse(response: AxiosResponse) {
  const disposition = response.headers['content-disposition'];
  const utf8FilenameRegex = /filename\*=UTF-8''([\w%\-.]+)(?:; ?|$)/i;
  const asciiFilenameRegex = /^filename=(["']?)(.*?[^\\])\1(?:; ?|$)/i;

  let fileName = '';
  if (utf8FilenameRegex.test(disposition)) {
    const arr = utf8FilenameRegex.exec(disposition);
    if (arr && arr.length >= 2) {
      fileName = decodeURIComponent(arr[1]);
    }
  } else {
    const filenameStart = disposition.toLowerCase().indexOf('filename=');
    if (filenameStart >= 0) {
      const partialDisposition = disposition.slice(filenameStart);
      const matches = asciiFilenameRegex.exec(partialDisposition);
      if (matches != null && matches[2]) {
        fileName = matches[2];
      }
    }
  }
  return fileName;
}

// 导出 axios 实例
export { service as request };
export default service;
